package testing_package;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class nbClient {

	/**
	 * @param args
	 */
	static int id;
	static int delay = 1000;
	static int port;	
	static boolean received = false;
	
	static synchronized void setReceived(boolean value){
		received = value;
	}
	
	public static void main(String[] args) throws Exception{
		
		if (args.length > 0){
			id = Integer.parseInt(args[0]);
		    port = Integer.parseInt(args[1]);
		    
		}
		else{
			id = 99;
			port = 4444;
		}
		// Create client SocketChannel
		SocketChannel client = SocketChannel.open();

		// nonblocking I/O
		client.configureBlocking(false);

		// Connection to host port 8000
		client.connect(new java.net.InetSocketAddress("localhost",port));		

		// Create selector
		Selector selector = Selector.open();

		//SelectionKey clientKey = client.register(selector, SelectionKey.OP_CONNECT);
		SelectionKey clientKey = client.register(selector, client.validOps());

		// Waiting for the connection
		
		while (selector.select(1000) > 0) {

		  // Get keys
		  Set keys = selector.selectedKeys();
		  Iterator i = keys.iterator();
		  Selector writeSelector = Selector.open();
		  Selector readSelector = Selector.open();

		  // For each key...
		  while (i.hasNext()) {
		    SelectionKey key = (SelectionKey)i.next();

		    // Remove the current key
		    i.remove();		 

		    // Get the socket channel held by the key
		    SocketChannel channel = (SocketChannel)key.channel();
		    		    
		    // Attempt a connection
		    if (key.isConnectable()) {

		      // Connection OK
		      System.out.println("Server Found");
		      
		      // Close pendency connections
		      if (channel.isConnectionPending())
		        channel.finishConnect();
		      //channel.close();
		      
		      channel.register(selector, SelectionKey.OP_WRITE);
		      channel.register(writeSelector, SelectionKey.OP_WRITE);		      		      

		    }
		    if (key.isWritable()){
		    	System.out.println("Ready for writing");
		    	
			      // Write on the buffer
			      ByteBuffer buffer = null;
			      int counter = 0;			      
			        buffer = 
			          ByteBuffer.wrap(
			            new String(" This is a very long message from Client " + id + " that should exceed the bufer by a bit").getBytes());
			        try{
			        	int outBytes = channel.write(buffer);
			        System.out.println(channel.isConnected());
			        System.out.println(outBytes);
			        buffer.clear();
			        buffer = ByteBuffer.wrap(new String("This is another test").getBytes());
			        outBytes = channel.write(buffer);
			        System.out.println(outBytes);
			        Thread.currentThread().sleep(1000);
			        //channel.close();
			        //break;
			        }
			        catch (Exception e){
			        	e.printStackTrace();
			        }
			        buffer.clear();
			        counter++;
			        
			        channel.register(selector, SelectionKey.OP_READ);
			        channel.register(readSelector, SelectionKey.OP_READ);
			        
			        Runnable temp = new nbThreadResponse(readSelector);
			        Thread t = new Thread(temp);
			        t.start();
			        
		    }
		    
		    if (key.isReadable()){
		    	System.out.println("Ready for reading");
		    }
		    
		  }
		}

	}

}


class nbThreadResponse implements Runnable{

	private Selector selector;
	public nbThreadResponse(Selector sel){
		selector = sel;
	}
	
	@Override
	public void run() {
		try {
			while (selector.select() > 0){
				
				System.out.println("Selecting Read");
				
				  // Get keys
				  Set keys = selector.selectedKeys();
				  Iterator i = keys.iterator();

				  // For each key...
				  while (i.hasNext()) {
				    SelectionKey key = (SelectionKey)i.next();

				    // Remove the current key
				    i.remove();		 

				    // Get the socket channel held by the key
				    SocketChannel channel = (SocketChannel)key.channel();
				    
				    if (key.isReadable()){
				    	ByteBuffer buf = ByteBuffer.allocate(1024);
				    	
						   StringBuilder msg = new StringBuilder();
						   for (;;) {
							   buf.clear();
						    int numBytesRead = channel.read(buf);
						    if (numBytesRead==-1)
						        break;
						    if (numBytesRead>0) {
						        buf.flip();
						        byte[] tempb = new byte[buf.remaining()];
						        buf.get(tempb); 
						        String s = new String(tempb);
						        msg.append(s);
						    }
						   }
				    	
				    }
				  }
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
	
}
